home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 201-225 / disk_217 / sonixpeek / src / sonixpeek.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  12KB  |  461 lines

  1. /*
  2.  * SONIXPEEK.C                              by Eddy Carroll, April 1988
  3.  * ~~~~~~~~~~~                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4.  *
  5.  * Scans one or more Aegis Sonix music files building a list of unique
  6.  * instruments used within those files. At the end, a list of the
  7.  * instruments found is printed (can be redirected to a file if
  8.  * desired).
  9.  *
  10.  * Usage: SonixPeek {-h} {-i} {-n} {-ofile} {-xdirectory} filename ...
  11.  *
  12.  * If filename is a Sonix file, then only that file is scanned. If
  13.  * filename is a directory, then all the files in that directory which
  14.  * contain Sonix files are scanned.
  15.  * 
  16.  * The -h flag suppresses the printing of the header which is normally
  17.  * present at the top of the list of instruments.
  18.  *
  19.  * If the -i (interactive) flag is present, then after each file is
  20.  * found, the user is asked whether it should be included or not when
  21.  * building the list of instruments.
  22.  *
  23.  * If the -o flag is present, then the list of instruments is stored
  24.  * in the specified file, rather than being displayed on the screen.
  25.  *
  26.  * If the -x flag is present, then the output is given in the form
  27.  * of an executable file which consists of a line for each instrument
  28.  * found of the form COPY <instrument> TO <directory>, where <directory>
  29.  * is given immediately after the -x switch.
  30.  *
  31.  * If the -n flag is present, then the list of instruments found in each
  32.  * file, when a directory is being searched, is not printed.
  33.  *
  34.  * DISTRIBUTION
  35.  * I retain copyright to the source and executable code for SonixPeek, but
  36.  * it may be freely redistributed as long as no profit is made from it.
  37.  * 
  38.  * Compiles under Lattice C V4.0
  39.  *
  40.  * Note: Some of this code is messy. Have patience with it :-)
  41.  *
  42.  */
  43.  
  44. #include <exec/types.h>
  45. #include <libraries/dos.h>
  46. #include <proto/exec.h>
  47. #include <proto/dos.h>
  48. #include <proto/intuition.h>
  49. #include <string.h>
  50.  
  51. /* The following is a quick hack to avoid having to link with lc.lib */
  52. #define strcat(p,q) (strcpy((p)+strlen(p),(q)))
  53.  
  54. /*
  55.  * New handler for Ctrl-C. Checks if CTRL-C received, and if it has, sets
  56.  * the global CtrlC variable to true.
  57.  */
  58. int CtrlC;
  59. #define chkabort() (CtrlC |= ((SetSignal(0,0) & SIGBREAKF_CTRL_C)))
  60.  
  61. #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) + 'a' - 'A' : (c))
  62.  
  63. #define EOL      '\012'
  64. #define EOF      '\037'
  65. #define TAB      '\011'
  66. #define CR       '\015'
  67.  
  68. #define MAXINS        1000    /* Only 200 instruments allowed        */
  69. #define MAXFILENUM    200        /* No more than 200 scores allowed    */
  70. #define MAXSTRING    256        /* Maximum length of a string        */
  71.  
  72. #define INDENT ("    ")        /* Amount to indent instruments by    */
  73.  
  74. /* IFF ID definitions */
  75.  
  76. #define MakeID(a,b,c,d) (long)((long)(a)<<24 | (long)(b)<<16 | (c)<<8 | (d))
  77. #define FORM MakeID('F','O','R','M')
  78. #define SMUS MakeID('S','M','U','S')
  79. #define NAME MakeID('N','A','M','E')
  80. #define SNX1 MakeID('S','N','X','1')
  81. #define INS1 MakeID('I','N','S','1')
  82. #define TRAK MakeID('T','R','A','K')
  83.  
  84. #define roundup(a) ((a + 1L) & ~1L)
  85.  
  86. int interactive;        /* TRUE if interactive selection of files            */
  87. int multi;                /* TRUE if a directory specified instead of file     */
  88. int supress;            /* TRUE if listing of instruments is supressed        */
  89. int noheader;            /* TRUE if no header ouput at start of instr. list    */
  90. char *dirname;            /* Directory to copy to for -x option                */
  91. char *suffix[] =
  92.     {".ss", ".instr"};    /* For creating 'copy' batch file                    */
  93.  
  94. LONG Examine(), ExNext(), Read(), Write();
  95. BPTR Lock(), CurrentDir();
  96.  
  97. int numins;                    /* Current number of instruments    */
  98. int numfiles;                /* Current number of files             */
  99. char *ins[MAXINS];            /* Room for 1000 instruments        */
  100. char *files[MAXFILENUM];    /* Room for 200 files                */
  101.  
  102. BPTR stdin, stdout, stderr, infile, outfile;
  103. struct FileInfoBlock myfib;
  104.  
  105. /*
  106.  *        The following lets us use our own version of malloc(). The only
  107.  *        additional requirements are that we open intuition.library first,
  108.  *        and call FreeRemember(&memkey,TRUE) just before exiting.
  109.  */
  110. struct Remember *memkey;    /* Used for tracking memory */
  111. #define malloc(n) (AllocRemember(&memkey,n,0L))
  112. struct IntuitionBase *IntuitionBase;
  113.  
  114. /*
  115.  *        Output string to file. Note that if CTRL-C has been typed,
  116.  *        output is suppressed.
  117.  */
  118.  
  119. void fprint(f, s)
  120. BPTR f;
  121. char *s;
  122. {
  123.     if (!CtrlC) {
  124.         Write(f, s, strlen(s));
  125.         chkabort();
  126.     }
  127. }
  128.  
  129. /*
  130.  *        Outputs 3 strings to file f (handy for printing "String" var "String")
  131.  *        The strings are concatenated first to ensure that they are printed
  132.  *        as a single unit, and won't be interrupted by ^C, or even just the
  133.  *        user pressing space, if the output is stdout or stderr.
  134.  */
  135. void fprint3(f,s1,s2,s3)
  136. BPTR f;
  137. char *s1,*s2,*s3;
  138. {
  139.     static char buf[MAXSTRING * 3];
  140.     strcpy(buf,s1);
  141.     strcat(buf,s2);
  142.     strcat(buf,s3);
  143.     fprint(f,buf);
  144. }
  145.  
  146. /*
  147.  *        print() and print3() are similar to fprint() and fprint3(), but
  148.  *        they output directly to stderr.
  149.  */
  150. #define print(s) fprint(stderr,s)
  151. #define print3(s1,s2,s3) fprint3(stderr,s1,s2,s3)
  152.  
  153. /*
  154.  *        Standard exit routine for program. Deallocates resources and exits.
  155.  *        If it spots CtrlC has been pressed, it prints an appropriate message.
  156.  */
  157.  
  158. void abort(code)
  159. int code;    /* Exit code */
  160. {
  161.     if (CtrlC)
  162.         Write(stderr,"^C\n",3);    /* print() won't work when CtrlC is true */
  163.     if (outfile != stdout && outfile != NULL)
  164.         Close(outfile);
  165.     if (stderr)
  166.         Close(stderr);
  167.     if (memkey)
  168.         FreeRemember(&memkey,TRUE);
  169.     if (IntuitionBase) 
  170.         CloseLibrary(IntuitionBase);
  171.     exit(code);
  172. }
  173.  
  174. /*
  175.  *        Prints help message to standard output
  176.  */
  177. void help()
  178. {
  179. fprint3(stderr,"\n\
  180. SonixPeek Instrument Lister Copyright Eddy Carroll April 1988\n\
  181. \n\
  182. Usage: SonixPeek {-h} {-i} {-n} {-ofile} {-xdirectory} file ...\n\
  183. \n\
  184. File is the Aegis Sonix file for which the instruments are to\n","\
  185. be listed. If it is a directory, then all the Sonix files in\n\
  186. that directory are checked, and a sorted list of the instruments\n\
  187. contained in all of them is prepared. The flags operate as follows:\n\
  188. \n","\
  189.  -h  Suppress output of header at start of instrument listing\n\
  190. \n\
  191.  -i  Ask user whether or not to include each score found\n\
  192. \n\
  193.  -n  Don't list instruments as they are found\n\
  194. \n");fprint(stderr,"\
  195.  -o  Redirect sorted output to named file\n\
  196. \n\
  197.  -x  Format output as an execute file which will copy all the\n\
  198.      instruments found to the named directory\n\
  199. \n");
  200. }
  201.  
  202. /*** Start of actual program ***/
  203.  
  204. void main(argc, argv)
  205. int argc;
  206. char *argv[];
  207. {
  208.  
  209.     void addinstrument(), skip(), dumpins();
  210.     char charin();
  211.     BPTR mylock, oldlock;
  212.     char *fname;
  213.  
  214.     stdin   = Input();
  215.     stderr  = Open("*",MODE_NEWFILE);
  216.     outfile = stdout = Output();
  217.     infile  = 0;
  218.  
  219.     if ((IntuitionBase = OpenLibrary("intuition.library",0L)) == NULL)
  220.         abort(99);
  221.  
  222.     /* Scan command line for possible switches */
  223.  
  224.     for ( argv++; argc > 1 && argv[0][0] == '-'; argc--,argv++) {
  225.         switch (tolower(argv[0][1])) {
  226.  
  227.         case 'h':    noheader = 1;
  228.                     break;
  229.  
  230.         case 'i':    interactive = 1;
  231.                     break;
  232.  
  233.         case 'n':   supress = 1;
  234.                     break;
  235.  
  236.         case 'o':    if ((outfile = Open(argv[0]+2,MODE_NEWFILE)) == 0) {
  237.                         print3("Can't open file ",argv[0]+2," for output.\n");
  238.                         abort(20);
  239.                     }
  240.                     break;
  241.  
  242.         case 'x':    dirname = argv[0] + 2;
  243.                     break;
  244.  
  245.         default:    print3("Unknown option ", argv[0], " ignored.\n");
  246.                     break;
  247.         }
  248.     }
  249.  
  250.     /* If missing filename, or filename == '?', print instructions */
  251.  
  252.     if (argc == 1 || argv[0][0] == '?') {
  253.         help();
  254.         abort(0);
  255.     }
  256.     if (argc > 2)    /* More than one file specified */
  257.         multi = 1;    /* so enable printing of instrument list for each file    */
  258.  
  259.     /*
  260.      *        Now scan each of the files or directories specified, reading
  261.      *        the instruments from each one, and adding them to the list.
  262.      */
  263.     for ( ; argc > 1; argc--, argv++) {
  264.         fname = argv[0];
  265.         if ((mylock = Lock(fname, ACCESS_READ)) == 0L) {
  266.             print3("Can't open file ",fname," for input.\n");
  267.             abort(20);
  268.         }
  269.         Examine(mylock,&myfib);
  270.         if (myfib.fib_DirEntryType > 0L) {
  271.             multi = 1;
  272.             oldlock = CurrentDir(mylock);
  273.             while (chkabort(), ExNext(mylock, &myfib) && !CtrlC)
  274.                 if (myfib.fib_DirEntryType < 0L)
  275.                     scan(&(myfib.fib_FileName), fname); 
  276.             oldlock = CurrentDir(oldlock);
  277.         } else
  278.             scan(fname,NULL);
  279.     }
  280.     dumpins();
  281.     UnLock(mylock);
  282.     abort(0);
  283. }
  284.  
  285. /*
  286.  *        Scans filename for instruments. If found, they are added to the
  287.  *        list of instruments already in memory. Returns 0 for success, -1
  288.  *        if invalid file. The path parameter, which may be NULL, is the
  289.  *        path to be prefixed to the filename before it is stored in memory.
  290.  *        Note that this may entail adding a trailing '/' to the path.
  291.  */
  292.  
  293. int scan(filename,path)
  294. char *filename;
  295. char *path;
  296. {
  297.     LONG header[3];
  298.     char instr[50], response[50], *p;
  299.     int plen, foundinstr = 0;
  300.  
  301.     if ((infile = Open(filename,MODE_OLDFILE)) == 0L) {
  302.         print3("Can't open file ", filename, " for input\n");
  303.         return(-1);
  304.     }
  305.  
  306.     if (Read(infile,(char *)header,8L) != 8L || header[0] != FORM) {
  307.         Close(infile);
  308.         return(-1);
  309.     }
  310.  
  311.     if (Read(infile,(char *)header,4L) != 4L || header[0] != SMUS) {
  312.         Close(infile);
  313.         return(-1);
  314.     }
  315.  
  316.     if (interactive) {
  317.         print3("Include file ", filename, " (CR = no)? ");
  318.         Read(stdin, response, 50L);
  319.         if (tolower(*response) != 'y')
  320.             return(-1);
  321.     } else if (multi && !supress)
  322.         fprint3(stdout, filename, ":\n", "");
  323.  
  324.     while (chkabort(), Read(infile,(char *)header,8L) == 8L && !CtrlC) {
  325.         if (header[0] != INS1) {
  326.             skip(infile,header[1]);
  327.         } else {
  328.             skip(infile,4L); /* skip position of instrument parameter */
  329.             Read(infile, instr, roundup(header[1]) - 4L);
  330.             instr[header[1] - 4L] = '\0';    /* Null-terminate string */
  331.             addinstrument(instr);
  332.             foundinstr = 1;
  333.         }
  334.     }
  335.     if (multi && !supress)
  336.         fprint(stdout,"\n");
  337.     if (foundinstr) {
  338.         if (path) {
  339.             plen = strlen(path);
  340.             p = malloc(strlen(filename)+plen+2);
  341.             /* Allocate extra byte for zero terminator and for possible '/' */
  342.             strcpy(p, path);
  343.             if (plen && p[plen-1] != ':' && p[plen-1] != '/')
  344.                 strcat(p,"/");
  345.             strcat(p,filename);
  346.         } else {
  347.             p = malloc(strlen(filename)+1);
  348.             strcpy(p,filename);
  349.         }
  350.         files[numfiles++] = p;
  351.     }
  352.     Close(infile);
  353.     return(0);
  354. }
  355.  
  356. void skip(file,size)
  357. BPTR file;
  358. LONG size;
  359. {
  360.     char s[256];
  361.     LONG len = 1L;
  362.     size = roundup(size);
  363.     while (chkabort(), size > 0 && len && !CtrlC) {
  364.         len = Read(file, s, (size > 256 ? 256 : size));
  365.         size -= 256;
  366.     }
  367. }
  368.  
  369.  
  370. /*
  371.  *        Adds instrument of length len into list of instruments, but only
  372.  *        if its not already present in the list.
  373.  */
  374.  
  375. void addinstrument(instr)
  376. char *instr;
  377. {
  378.     int pos, i;
  379.     if ((pos = matchins(instr)) != -1) {
  380.         for (i = numins++; i > pos; i--)
  381.             ins[i] = ins[i-1];
  382.         ins[pos] = malloc(strlen(instr)+1);
  383.         strcpy(ins[pos], instr);
  384.     }
  385.     if (multi && !supress) {
  386.         fprint3(stdout, INDENT, instr, "\n");
  387.     }
  388. }
  389.  
  390. /*
  391.  *        Compares string p to string s, ignoring case of alpha chars.
  392.  *        Returns -ve if p < s, 0 if p = s, +ve if p > s.
  393.  */
  394.  
  395. int mystrcmp(p,s)
  396. char *p, *s;
  397. {
  398.     while (*p && *s && tolower(*p) == tolower(*s))
  399.         p++, s++;
  400.     return(tolower(*p) - tolower(*s));
  401. }
  402.  
  403. /*
  404.  *        Searches instrument array for a match with given instrument. 
  405.  *        Returns -1 if found, else position in array to insert new element.
  406.  */
  407.  
  408. int matchins(instr)
  409. char *instr;
  410. {
  411.     int i, z;
  412.  
  413.     for (i = 0; i < numins; i++) {
  414.         if ((z = mystrcmp(instr, ins[i])) <= 0) {
  415.             if (z)
  416.                 return(i); /* If less, insert here */
  417.             else
  418.                 return(-1); /* If equal, don't insert  */
  419.         }
  420.     }
  421.     return (i); /* Must be at end of list, so return last item */
  422. }
  423.  
  424. /*
  425.  *        Dumps instrument list to outfile
  426.  */
  427. void dumpins()
  428. {
  429.     int i, j;
  430.  
  431.     if (numins == 0) {
  432.         print("No instruments found.\n");
  433.         return;
  434.     }
  435.  
  436.     if (!noheader) {
  437.         fprint(outfile,";\n; Sorted list of instruments\n");
  438.         fprint(outfile,   "; --------------------------\n;\n");
  439.         if (numfiles == 1)
  440.             fprint3(outfile, "; Taken from file ", files[0], "\n");
  441.         else {
  442.             fprint(outfile,"; Taken from these files:\n;\n");
  443.             for (i = 0; i < numfiles && !CtrlC; i++) {
  444.                 fprint3(outfile, ";     ", files[i], "\n");
  445.             }
  446.         }
  447.         fprint(outfile,";\n");
  448.     }
  449.     if (dirname)
  450.         fprint(outfile,"failat 30\n");
  451.     for (i = 0; i < numins && !CtrlC; i++) {
  452.         for (j = (dirname != 0); j >= 0 && !CtrlC; j--) {
  453.             if (dirname) {
  454.                 fprint3(outfile, "copy ", ins[i], " to ");
  455.                 fprint3(outfile, dirname, "\n", "");
  456.             } else
  457.                 fprint3(outfile, INDENT, ins[i], "\n");
  458.         }
  459.     }
  460. }
  461.